package awk.reflect;


import awk.model.animal.Dog;
import awk.proxy.TaskImpl;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import sun.reflect.ReflectionFactory;

/**
 * @description:
 * @author: wanghaifeng
 * @date: 2021/3/2
 * https://blog.csdn.net/weixin_39935887/article/details/81541871
 * Reflection类是一个反射工具类，在代理/反射中频繁使用。查看其方法：
 * isSameClassPackage
 * verifyMemberAccess
 * ensureMemberAccess
 * getClassAccessFlags
 * 等在 Class Proxy AccessibleObject等类中频繁使用
 *
 * 反射三种方式
 */
public class ReflectionUtils3 {

    public static void main(String[] args) throws Exception {
        //反射方式一
        Class clazz = Class.forName(TaskImpl.class.getName());
        TaskImpl task = (TaskImpl)clazz.newInstance();//如果不是内部类则没问题,如果是内部类,需要换一种写法
        task.add();

        //反射方式二
        //要获取内部类的constructor，getConstructor()第一个参数是外部类的class文件，然后才是内部类构造函数的形参
        Constructor<?> constructors = Class.forName(Group.class.getName()).getConstructor(ReflectionUtils3.class, String.class, int.class);
        Group group = (Group)constructors.newInstance(new ReflectionUtils3(),"tom",3);
        group.sayHello();

        //反射方式三   这里获取所有的构造,然后比对参数数量
        //要获取内部类的constructor，getConstructor()第一个参数是外部类的class文件，然后才是内部类构造函数的形参
        Group group23 = (Group)newObjectInstance(Group.class,new ReflectionUtils3(),"tom",3);
        System.out.println(group23.name);


        //反射方式四
        //newConstructorForSerialization() 不需要构造参数就可以获取，所以其可以做到不调用默认构造参数就可以实例化对象。
        //实现原理:Constructor 对象中有一个关键属性 private volatile ConstructorAccessor constructorAccessor;
        // ConstructorAccessor 是一个接口 如果构造方法不存在是没有办法反射生成的，
        //而newConstructorForSerialization() 方法使用字节码的方式生成了这个接口的实现类。
        Constructor<?> constructor = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(Group.class, Object.class.getDeclaredConstructor());
        constructor.setAccessible(true);
        Group instance = (Group)constructor.newInstance();
        System.out.println(instance.getClass().getName());

/////////////////////////////////////////构造器///////////////////////////////////////////////
        Class<?> class1 = Dog.class;
        Constructor<?>[] constructors2 = class1.getConstructors();
        Dog dog2 = (Dog) constructors2[0].newInstance();
        //给对象赋值
        dog2.setAge(30);
        dog2.setName("Hongten");
        //通过构造器直接赋值
        Dog dog4 = (Dog) constructors2[1].newInstance("Hongten",20);

        // 取得父类名称
        Class<?> superClass = class1.getSuperclass();
        System.out.println("Demo6:  SuperMan类的父类名: " + superClass.getName());
        // 取得类实现的接口
        Class<?> interfaces[] = class1.getInterfaces();
        for (int i = 0; i < interfaces.length; i++) {
            //运行结果：实现的接口类名: com.b510.hongten.test.reflex.ActionInterface
            System.out.println("实现的接口类名: " + interfaces[i].getName());
        }

        //field
        Field personNameField = class1.getDeclaredField("name");
        personNameField.setAccessible(true);
        personNameField.set(dog2, "HONGTEN");
        System.out.println("修改属性之后得到属性变量的值：" + personNameField.get(dog2));
        Field[] fields = class1.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            System.out.println("类中的成员: " + fields[i]);
        }
        // 取得方法
        Method[] methods = class1.getDeclaredMethods();
        for (Method method : methods) {
            String name = method.getName();
            Class<?> returnType = method.getReturnType();
            String modifiers = Modifier.toString(method.getModifiers());
            System.out.println("函数名：" + name + "函数返回类型：" + returnType + "函数访问修饰符：" + modifiers+"函数代码写法： " + method);
        }

        //method.invoke
        Method method = class1.getMethod("eat");
        method.invoke(class1.newInstance());
        method = class1.getMethod("eat", String.class);
        method.invoke(class1.newInstance(), "骨头");
    }


    class Group{
        String name = "defaultName";
        int total = 0;
        public Group(String name,int total){
            this.name = name;
            this.total = total;
        }

        public Group(){}

        public void sayHello(){
            System.out.println("hello...");
        }
    }


    ///////////////////////////////instance///////////////////////////////////

    /**
     * 通过反射创建对象
     */
    public static Object newObjectInstance(Class<?> clazz, Object... constructArgs) {
        Object object;
        try {
            object = null;
            List<Constructor<?>> constructorsAll = getConstructorsAll(clazz);
            for (Constructor<?> constructor : constructorsAll) {
                if (constructor.getParameterCount() == constructArgs.length) {
                    //使构造器可以被访问
                    if ((!Modifier.isPublic(constructor.getModifiers()) ||
                            !Modifier.isPublic(constructor.getDeclaringClass().getModifiers())) && !constructor.isAccessible()) {
                        constructor.setAccessible(true);
                    }
                    object = constructor.newInstance(constructArgs);
                }
            }
        } catch (Exception e) {
            object = null;
        }
        return object;
    }

    //////////////////////////////////////////field///////////////////////////////////////////////
    public static boolean setFieldValue(Object o, String name, Object value) {
        boolean result;
        try {
            Field field = o.getClass().getDeclaredField(name);
            makeFieldAccessible(field);
            field.set(o, value);
            result = true;
        } catch (Exception e) {
            result = false;
        }
        return result;
    }

    public static Object getFieldValue(Object o, String name) {
        Object value;
        try {
            Field field = o.getClass().getDeclaredField(name);
            makeFieldAccessible(field);
            value = field.get(o);
        } catch (Exception e) {
            value = null;
        }
        return value;
    }


    /**
     * 获取字段类型 类名称（去除包名）
     *
     * @param field
     * @return
     */
    public static String getFieldTypeNameShort(Field field) {
        if (field == null) {
            return "";
        }
        String allName = field.getType().getName();
        if (allName.isEmpty()) {
            return "";
        }
        if (!allName.contains(".")) {
            return allName;
        }
        return allName.substring(allName.lastIndexOf(".") + 1, allName.length());
    }

    /**
     * 获取字段类型 类名称（包含包名）
     */
    public static String getFieldTypeNameEntire(Field field) {
        if (field == null) {
            return "";
        }
        return field.getType().getName();
    }

    public static List<Field> getFieldsAll(Class<?> clazz) {
        List<Field> fieldList = new ArrayList<>();
        if (clazz == null) {
            return fieldList;
        }
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            fieldList.add(field);
        }
        return fieldList;
    }


    /**
     * 字段是否被 public static final 修饰
     */
    public static boolean isFieldPublicStaticFinal(Field field) {
        int modifiers = field.getModifiers();
        return (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers));
    }

    public static boolean isFieldStatic(Field field) {
        int modifiers = field.getModifiers();
        return Modifier.isStatic(modifiers);
    }

    public static boolean isFieldFinal(Field field) {
        int modifiers = field.getModifiers();
        return Modifier.isFinal(modifiers);
    }

    public static boolean isFieldPrivate(Field field) {
        int modifiers = field.getModifiers();
        return Modifier.isPrivate(modifiers);
    }

    public static boolean isFieldPublic(Field field) {
        int modifiers = field.getModifiers();
        return Modifier.isPublic(modifiers);
    }

    /**
     * 使字段可以被访问
     *
     * @param field
     */
    public static void makeFieldAccessible(Field field) {
        if ((!Modifier.isPublic(field.getModifiers()) ||
                !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) {
            field.setAccessible(true);
        }
    }

    ///////////////////////////////////classname/////////////////////////////////////////////////
    /**
     * 获取类名称（去除包名）
     */
    public static String getClassNameShort(Class<?> clazz) {
        if (clazz == null) {
            return "";
        }
        String allName = clazz.getName();
        if (allName.isEmpty()) {
            return "";
        }
        if (!allName.contains(".")) {
            return allName;
        }
        return allName.substring(allName.lastIndexOf(".") + 1, allName.length());
    }

    ////////////////////////////////Constructor//////////////////////////////////

    public static boolean isConstructorPublic(Constructor<?> constructor) {
        int modifiers = constructor.getModifiers();
        return Modifier.isPublic(modifiers);
    }

    /**
     * 构造器是否被 private 修饰
     */
    public static boolean isConstructorPrivate(Constructor<?> constructor) {
        int modifiers = constructor.getModifiers();
        return Modifier.isPrivate(modifiers);
    }

    public static List<Constructor<?>> getConstructorsAll(Class<?> clazz) {
        List<Constructor<?>> constructors = new ArrayList<>();
        if (clazz == null) {
            return constructors;
        }
        Constructor<?>[] constructorsArray = clazz.getDeclaredConstructors();
        for (Constructor<?> constructor : constructorsArray) {
            constructors.add(constructor);
        }
        return constructors;
    }

    /**
     * 使构造器可以被访问
     * @param constructor
     */
    public static void makeConstructorAccessible(Constructor<?> constructor) {
        //使构造器可以被访问
        if ((!Modifier.isPublic(constructor.getModifiers()) ||
                !Modifier.isPublic(constructor.getDeclaringClass().getModifiers())) && !constructor.isAccessible()) {
            constructor.setAccessible(true);
        }
    }

    //////////////////////////////method///////////////////////////////////////
    /**
     * 使方法可以被访问
     */
    public static void makeMethodAccessible(Method method) {
        if ((!Modifier.isPublic(method.getModifiers()) ||
                !Modifier.isPublic(method.getDeclaringClass().getModifiers()) ||
                Modifier.isFinal(method.getModifiers())) && !method.isAccessible()) {
            method.setAccessible(true);
        }
    }



}

